"""
OpenTelemetry 初始化模块

说明：
1. 使用 OTLP 导出器将 Trace/Metric/Log 导出到 OTel Collector（或 APM 平台）
2. 支持通过环境变量配置导出端点、服务名等参数
3. 自动接入 FastAPI、Requests，统一 TraceId 传播
"""

from typing import Optional

import os

from opentelemetry import metrics, trace
from opentelemetry.exporter.otlp.proto.http.metric_exporter import (
    OTLPMetricExporter,
)
from opentelemetry.exporter.otlp.proto.http.trace_exporter import (
    OTLPSpanExporter,
)
from opentelemetry.sdk.metrics import MeterProvider
from opentelemetry.sdk.metrics.export import PeriodicExportingMetricReader
from opentelemetry.sdk.resources import Resource
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor

from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor
from opentelemetry.instrumentation.requests import RequestsInstrumentor


def _build_resource(service_name: str) -> Resource:
    """构建 Resource 对象。

    1. 合并环境变量中预设的资源属性
    2. 覆盖 service.name 为入参
    """
    env_resource = Resource.create()
    return env_resource.merge(Resource.create({"service.name": service_name}))


def _get_env(name: str, default: Optional[str] = None) -> Optional[str]:
    """读取环境变量，若为空字符串则返回默认值。

    1. 优先返回非空值
    2. 否则返回默认值
    """
    value = os.getenv(name)
    if value is None or value.strip() == "":
        return default
    return value


def init_otel(service_name: str = "otel-fastapi-demo") -> None:
    """初始化 OpenTelemetry。

    1. 组装 Resource，设置 service.name
    2. 配置 TracerProvider + BatchSpanProcessor + OTLPSpanExporter
    3. 配置 MeterProvider + PeriodicExportingMetricReader + OTLPMetricExporter
    4. 自动接入 FastAPI/Requests，启用分布式上下文传播
    """
    # 1. 读取环境变量
    otlp_endpoint = _get_env("OTEL_EXPORTER_OTLP_ENDPOINT", "http://localhost:4318")
    otlp_headers = _get_env("OTEL_EXPORTER_OTLP_HEADERS")

    # 2. 构建资源
    resource = _build_resource(service_name)

    # 3. 配置 Tracing
    tracer_provider = TracerProvider(resource=resource)
    span_exporter = OTLPSpanExporter(
        endpoint=f"{otlp_endpoint}/v1/traces",
        headers=dict(
            item.split("=") for item in otlp_headers.split(",")
        )
        if otlp_headers
        else None,
    )
    span_processor = BatchSpanProcessor(span_exporter)
    tracer_provider.add_span_processor(span_processor)
    trace.set_tracer_provider(tracer_provider)

    # 4. 配置 Metrics（可选）
    metric_exporter = OTLPMetricExporter(
        endpoint=f"{otlp_endpoint}/v1/metrics",
        headers=dict(
            item.split("=") for item in otlp_headers.split(",")
        )
        if otlp_headers
        else None,
    )
    metric_reader = PeriodicExportingMetricReader(metric_exporter)
    meter_provider = MeterProvider(resource=resource, metric_readers=[metric_reader])
    metrics.set_meter_provider(meter_provider)

    # 5. 自动接入
    RequestsInstrumentor().instrument()
    # FastAPIInstrumentor 需要在 FastAPI app 实例创建后调用


def instrument_fastapi_app(app) -> None:
    """对 FastAPI 实例进行自动接入。

    1. 安装路由中间件，记录请求/响应 span
    2. 记录异常与状态码
    """
    FastAPIInstrumentor.instrument_app(app)


